/**
 *  Copyright 2007-2008 University Of Southern California
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package edu.isi.pegasus.workflowsim.clusering;

import edu.isi.pegasus.workflowsim.Task;
import edu.isi.pegasus.workflowsim.utils.Parameters;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import org.cloudbus.cloudsim.Log;

/**
 *
 * @author Weiwei Chen
 */
public class VerticalClustering extends BasicClustering{
    
    private int mDepth;
    private Map mHasChecked;
    

    public VerticalClustering(int depth){
        super();
        this.mDepth      = depth;
        this.mHasChecked = new HashMap<Integer, Boolean>();
        

    }
    
    private void setCheck(int index){
        
        if(mHasChecked.containsKey(index)){
            mHasChecked.remove(index);
        }
        mHasChecked.put(index, true);
        
                
    }
    private boolean getCheck(int index){

        if(mHasChecked.containsKey(index)){
            return (Boolean)mHasChecked.get(index);
        }
        return false;
    }
    
    @Override
    public void run()
 
    {
        if(mDepth >0 ){
            
            if(Parameters.getReduceMethod().equals("montage")){
                removeDuplicateMontage();
            }
            Task root = super.addRoot();
            Task node = root;
            ArrayList taskList = new ArrayList<Task>();
            Stack stack = new Stack<Task>();
            stack.push(root);
            while(!stack.empty()){
                node = (Task)stack.pop();
                if(!getCheck(node.getCloudletId())){
                    setCheck(node.getCloudletId());
                    
                    int pNum = node.getParentList().size();
                    int cNum = node.getChildList().size();
                    
                    for(Iterator it = node.getChildList().iterator(); it.hasNext();){
                            Task cNode = (Task)it.next();
                            stack.push(cNode);
                    }
                    
                    if(pNum ==0 ){
                        //root skip it
                    }else if (pNum > 1){
                        if(cNum > 1||cNum == 0){

                            
                            if(!taskList.isEmpty()){
                                addTasks2Job(taskList);
                                taskList.clear();
                            }
                            taskList.add(node);
                            addTasks2Job(taskList);
                            taskList.clear();
                           
                        }else {//cNum==1
                            //cut and add new
                            
                            if(!taskList.isEmpty()){
                                addTasks2Job(taskList);
                                taskList.clear();
                            }
                            if(!taskList.contains(node))
                                taskList.add(node);
                        }
                    }else{//pNum == 1
                        if(cNum > 1||cNum == 0){
                            //This is different to the case of pNum > 1
                            taskList.add(node);
                            addTasks2Job(taskList);
                            taskList.clear();
                        }else{
                            //This is also different to the case of pNum > 1
                            if(!taskList.contains(node))
                                taskList.add(node);
                        }
                    }
                                      
                }else{
                    if(!taskList.isEmpty()){
                        addTasks2Job(taskList);
                        taskList.clear();
                    }
                }
                
                
                
            }

        }
        mHasChecked.clear();
        super.clean();

        updateDependencies();
        addClustDelay();
    }
    
        public void removeDuplicateMontage(){

        List jobList = this.getTaskList();
        for(int i = 0; i < jobList.size(); i++){
            Task node = (Task)jobList.get(i);
            String name = node.getType();
            if(name.equals("mBackground")){
                //remove all of its parents of mProjectPP
                
                 for(int j = 0; j < node.getParentList().size(); j++){
                     
                    Task parent = (Task)node.getParentList().get(j);
                    if(parent.getType().equals("mProjectPP")){
                        j--;
                        node.getParentList().remove(parent);
                        parent.getChildList().remove(node);
                    }
                 }
                
            }else if(name.equals("mAdd")){
                 for(int j = 0; j < node.getParentList().size(); j++){
                     
                    Task parent = (Task)node.getParentList().get(j);
                    String pName = parent.getType();
                    if(pName.equals("mBackground")||pName.equals("mShrink")){
                        j--;
                        node.getParentList().remove(parent);
                        parent.getChildList().remove(node);
                    }
                 }                
            }
        }
        
    }
    
    
}
